package xyz.cerberu.cet.user.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import xyz.cerberu.cet.global.domain.ExceptionEncode;
import xyz.cerberu.cet.global.domain.Result;
import xyz.cerberu.cet.global.utils.*;
import xyz.cerberu.cet.shiro.utils.ShiroUtils;
import xyz.cerberu.cet.user.domain.PictureDTO;
import xyz.cerberu.cet.user.domain.User;
import xyz.cerberu.cet.user.exception.UploadCountException;
import xyz.cerberu.cet.user.service.PictureService;
import xyz.cerberu.cet.user.service.UserServiceImpl;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;

/**
 * @author β世界
 * Created on 15:21
 * @Description 用户的基本信息管理器
 */
@Controller
@RequestMapping("/user/")
public class BaseInfoControl {
    /** 用户服务的基本实现 **/
    private final UserServiceImpl userService;
    private final PictureService pictureService;
    private final static String AES_KEY = "NWSZLGSCQWUYSGQS";

    @Value("${global.remember-me-cookie-name}")
    private String rememberMeCookieName;

    /** 上传文件的时间差,单位是秒，默认情况下是30秒的间隔 **/
    private final static long TIME_LAG = 30;

    @Autowired
    public BaseInfoControl(UserServiceImpl userService,PictureService pictureService) {
        this.userService = userService;
        this.pictureService = pictureService;
    }

    /**
     * @author β世界 on 20:34 2021/2/15
     * 获取用户的基本信息
     * @return com.cet.common.domain.Result
     **/
    @RequestMapping(value = "info",method = RequestMethod.GET)
    @ResponseBody
    @RequiresUser
    public Result<Object> baseInfo(){
        Result<Object> result;
        Subject subject = SecurityUtils.getSubject();
        // 获取用户实体
        User user = (User)subject.getPrincipal();
        // 装填用户的信息
        Map<String,Object> map = new HashMap<>();
        map.put("name",user.getUsername());
        map.put("picture",user.getPicture());
        map.put("signature","摸鱼中，不想写简介");
        result = ResultUtils.genSuccessResult(map);
        return result;
    }


    /**
     * 保存用户更改的信息
     * @author β世界 on 13:30 2021/6/4
     * @param username: 用户名
     * @return xyz.cerberu.cet.global.domain.Result<java.lang.Object>
     **/
    @RequestMapping(value = "save",method = RequestMethod.POST)
    @ResponseBody
    @RequiresUser
    public Result<Object> saveSetting(String username,HttpServletRequest request){
        Result<Object> result = ResultUtils.genSuccessResult("OK");
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        // 检测是否包含特殊字符
        if(StringUtils.legal(username) || "".equals(username.trim())){
            return ResultUtils.genErrorResult(HttpStatus.SC_UNAUTHORIZED, "输入内容包含特殊-和_以外的特殊字符");
        }
        // 更新用户信息
        user.setUsername(username);
        if(userService.updateBaseInfo(user) != 1){
            result = ResultUtils.genErrorResult(HttpStatus.SC_NOT_IMPLEMENTED,"保存设定失败");
        }else{
            // 刷新shiro中的用户信息
            ShiroUtils.flushUser(user);
            flushRememberMeInfo(request, subject.getPreviousPrincipals());
        }

        return result;
    }

    /**
     * @author β世界 on 9:08 2021/3/30
     * 头像上传服务，用户上传上来我们需要对用户的上传次数进行判断（是否超出上传次数）
     *
     * @param file: 上传的文件
     * @return xyz.cerberu.cet.global.domain.Result<java.lang.Object>
     **/
    @RequiresUser
    @ResponseBody
    @RequestMapping(value = "uploadPicture",method = RequestMethod.POST)
    public Result<Object> uploadPicture(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        // 对用户的上传限制进行判断
        User user = (User)SecurityUtils.getSubject().getPrincipal();
        // 获取最后的上传时间
        JSONObject jsonObject = JSON.parseObject(AESUtils.decode(user.getPicture(), AES_KEY));
        // 获取最后的上传时间
        long lastUpload = jsonObject.getLong("lastUpload");
        long nowTime = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
        // 计算时间差，如果时间差小于一个小时就抛出上传次数异常
        if((nowTime-lastUpload) <= TIME_LAG){
            throw new UploadCountException("用户上传次数上限");
        }

        // 检查文件是否为空
        if(file.isEmpty()){
            return ResultUtils.genErrorResult(ExceptionEncode.PARAM_EXCEPTION,"文件内容为空");
        }

        // 封装业务对象
        PictureDTO pictureDTO = new PictureDTO();
        pictureDTO.setFileName(file.getOriginalFilename());
        // 设置用户ID
        pictureDTO.setFileType(file.getContentType());
        String pictureId = null;
        try {
            // 接收最后获取图片id
            pictureId = pictureService.uploadPicture(file.getInputStream(), pictureDTO);
            // 刷新记住我和会话中的用户信息
            user.setPicture(pictureId);
            // 修改数据库中的信息
            userService.updateBaseInfo(user);
            ShiroUtils.flushUser(user);
            flushRememberMeInfo(request,SecurityUtils.getSubject().getPrincipals());
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String,String> map = new HashMap<>();
        map.put("picture",pictureId);
        return ResultUtils.genSuccessResult(map);
    }

    /**
     * @author β世界 on 8:24 2021/3/31
     * 获取图片相关内容，根据pictureId来获取
     * @param pictureId: 图片的标识id
     * @return xyz.cerberu.cet.global.domain.Result<java.lang.Object>
     **/
    @RequestMapping(value = "picture",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
    public void getPicture(@RequestParam("pictureId") String pictureId
            ,@RequestParam(value = "width",required = false) Integer width
            ,@RequestParam(value = "height",required = false) Integer height, HttpServletResponse response) throws Exception {
        // 获取到图片的源数据
        byte[] originalData = IOUtils.toByteArray(pictureService.getPicture(pictureId));
        // 检查是否需要压缩
        if(width != null && width != 0 && height != null && height != 0){
            originalData = ImageUtils.compressImage(originalData,width,height);
        }
        response.getOutputStream().write(originalData);
        // 设置相应状态为图片
        response.setContentType("image/png,image/gif,image/webp,image/jpeg");
        response.flushBuffer();
    }

    /**
     * 刷新记住我的用户信息
     * @author β世界 on 13:27 2021/6/4
     * @param request: 请求实体
     * @return void
     **/
    private void flushRememberMeInfo(HttpServletRequest request, PrincipalCollection principalCollection){
        Cookie rememberMeCookie = RequestUtils.getCookie(request,rememberMeCookieName);
        if(rememberMeCookie != null){
            userService.flushUser(principalCollection,rememberMeCookie.getValue());
        }
    }
}
